#include "stratum.h"

void dbCheckUserInput(char* input) {
    char* p = nullptr;
    if (input && input[0]) {
        p = strpbrk(input, "\"\\");
        if (p) {
            *p= '\0';
        }
    }
}

void dbCheckCoinSymbol(StratumDB* db, char* symbol) {
    if (!symbol) {
        return;
    }

    size_t len = strlen(symbol);
    if (len >= 2 && len <= 12) {
#ifdef NO_EXCHANGE
        dbQuery(db, "SELECT symbol FROM coins WHERE installed AND algo='%s' AND = symbol='%s'", g_stratum_algo, symbol);
#else
        dbQuery(db, "SELECT symbol FROM coins WHERE installed AND (symbol='%s' OR symbol2='%s')", symbol, symbol);
#endif
        MYSQL_RES* res = mysql_store_result(&db->mysql);
        *symbol = '\0';
        if (!res) {
            return ;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        if (row) {
            strcpy(symbol, row[0]);
        }
        mysql_free_result(res);
    } else {
        *symbol = '\0';
    }
}

void dbAddUser(StratumDB* db, StratumClient* client) {
    dbCleanString(db, client->m_username);
    dbCleanString(db, client->m_password);
    dbCleanString(db, client->m_version);
    dbCleanString(db, client->m_notify_id);
    dbCleanString(db, client->m_worker);
    char symbol[16] = {};
    // 查找第一次出现字符串的位置
    char* p = strstr(client->m_password, "c=");
    if (!p) {
        p = strstr(client->m_password, "s=");
    }
    if (p) {
        strncpy(symbol, p+2, 15);
    }
    p = strchr(symbol, ',');
    if (p) {
        *p = '\0';
    }
    bool guest = false;
    int gift = -1;
#ifdef ALLOW_CUSTOM_DONATIONS
    p = strstr(client->password, "g=");
    if (p) {
        gift = atoi(p+2);
    }
    if (gift > 100) {
        gift = 100;
    }
#endif
    dbCheckUserInput(client->m_username);
    if (strlen(client->m_username) < MIN_ADDRESS_LEN) {
        if (!strcmp(client->m_username, "benchmark") || !strcmp(client->m_username, "donate") || !strcmp(client->m_username, "test")) {
            guest = true;
            if (g_list_coind.m_first) {
                PCLI li = g_list_coind.m_first;
                StratumCoind* coind = (StratumCoind*)li->data;
                if (!strlen(client->m_worker)) {
                    strcpy(client->m_worker, client->m_username);
                }
                strcpy(client->m_username, coind->m_wallet);
                if (!strcmp(client->m_username, "benchmark")) {
                    // 把",stats"所指向的字符串追加到password
                    strcat(client->m_password, ",stats");
                }
                if (!strcmp(client->m_username, "donate")) {
                    gift = 100;
                }
            }
        }
        if (!guest) {
            debuglog("invalid user address '%s'\n", client->m_username);
            return;
        }
    }

    dbQuery(db, "SELECT id,is_locked,logtraffic,coinid,donation FROM accounts WHERE username='%s'", client->m_username);
    MYSQL_RES* res = mysql_store_result(&db->mysql);
    if (!res) {
        return;
    }

    MYSQL_ROW row = mysql_fetch_row(res);
    if (row) {
        if (row[1] && atoi(row[1])) {
            client->m_user_id = -1;
        } else {
            client->m_user_id = atoi(row[0]);
        }

        client->m_log_traffic = row[2] && atoi(row[2]);
        client->m_coin_id = row[3] ? atoi(row[3]) : 0;
        if (gift == -1) {
            gift = row[4] ? atoi(row[4]) : 0;
        }
    }

    mysql_free_result(res);

    dbCheckUserInput(symbol);
    dbCheckCoinSymbol(db, symbol);
    if (gift < 0) {
        client->m_donation = gift;
    }
    if (client->m_user_id == -1) {
        return;
    } else if (client->m_user_id == 0 && strlen(client->m_username) >= MIN_ADDRESS_LEN) {
        dbQuery(db, "INSERT INTO accounts (username, coinsymbol, balance, donation, hostaddr) values ('%s', '%s', 0, %d, '%s')",
                client->m_username, symbol, gift, client->m_sock->m_ip);
        client->m_user_id = (int)mysql_insert_id(&db->mysql);
    } else {
        dbQuery(db, "UPDATE accounts SET coinsymbol='%s', swap_time=%u, donation=%d, hostaddr='%s' WHERE id=%d AND balance = 0 "
                    "AND (SELECT COUNT(id) FROM payouts WHERE account_id=%d AND tx IS NULL) = 0 " // failed balance
                    "AND (SELECT pending FROM balanceuser WHERE userid=%d ORDER by time DESC LIMIT 1) = 0", // pending balance
                    symbol, (uint)time(NULL), gift, client->m_sock->m_ip, client->m_user_id, client->m_user_id, client->m_user_id, client->m_user_id);
        if (mysql_affected_rows(&db->mysql) > 0 && strlen(symbol)) {
            debuglog("%s: %s coinsymbol set to %s ip %s uid (%d)\n",
                     g_current_algo->m_name, client->m_username, symbol, client->m_sock->m_ip, client->m_user_id);
        }
    }

}


void dbClearWorker(StratumDB* db, StratumClient* client) {
    if (!client->m_worker_id) {
        return ;
    }
    dbQuery(db, "", client->m_worker_id);
    client->m_worker_id = 0;
}

void dbAddWorker(StratumDB* db, StratumClient* client) {
    char password[128] = {0};
    char version[128] = {0};
    char worker[128] = {0};
    int now = time(nullptr);

    dbClearWorker(db, client);
    dbCheckUserInput(client->m_username);
    dbCheckUserInput(client->m_version);
    dbCheckUserInput(client->m_password);
    dbCheckUserInput(client->m_worker);

    if (strlen(client->m_password) > 64) {
        clientlog(client, "password too long truncated: %s", client->m_password);
    }
    if (strlen(client->m_version) > 64) {
        clientlog(client, "version too long truncated: %s", client->m_version);
    }
    if (strlen(client->m_worker) > 64) {
        clientlog(client, "worker too long truncated: %s", client->m_worker);
    }

    strncpy(password, client->m_password, 64);
    strncpy(version, client->m_version, 64);
    strncpy(worker, client->m_worker, 64);

    client->m_worker_id = (int)mysql_insert_id(&db->mysql);
}

void dbUpdateWorkers(StratumDB* db) {
    g_list_client.enter();

    for (PCLI li = g_list_client.m_first; li; li = li->next) {
        StratumClient* client = (StratumClient*)li->data;
        if (client->m_deleted) {
            continue;
        }
        if (!client->m_worker_id) {
            continue;
        }

        if (client->m_speed < 0.00001) {
            clientlog(client, "speed %f", client->m_speed);
            shutdown(client->m_sock->m_sock, SHUT_RDWR);
            dbClearWorker(db, client);
            objectDelete((StratumObject*)(client));
            continue;
        }

        client->m_speed *= 0.8;
        if (client->m_diff_written == client->m_diff_actual) {
            continue;
        }

    }

    g_list_client.leave();
}



